package com.elite.km.util;

import cn.hutool.core.util.StrUtil;
import com.elite.km.bean.*;
import com.elite.km.config.Config;
import com.elite.km.constant.Constants;
import com.elite.km.entity.LoginUser;
import com.elite.km.exception.KMException;
import com.elite.km.service.IArticleLockService;
import com.elite.km.service.RestTemplateService;
import com.elite.km.tree.TreeDao;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Locale;

/**
 * @description:
 * @author: sher
 * @create: 2020-06-24 10:21
 */
@Slf4j
@Component
public class TokenUtils {

    private static Config config;
    private static TreeDao treeDao;
    private static IArticleLockService articleLockService;
    private static RestTemplateService restTemplateService;
    private static final String ERRORMESSAGE = "km.token.check";
    public static final String STAFF = "staff";

    @Autowired
    public void setConfig(Config config) {
        TokenUtils.config = config;
    }
    @Autowired
    public void setTreeDao(TreeDao treeDao) {
        TokenUtils.treeDao = treeDao;
    }
    @Autowired
    public void setArticleLockService(IArticleLockService articleLockService) {
        TokenUtils.articleLockService = articleLockService;
    }
    @Autowired
    public void setRestTemplateService(RestTemplateService restTemplateService) {
        TokenUtils.restTemplateService = restTemplateService;
    }
    /**
     * 调用token接口 获取登录信息
     *
     * @param token
     * @param ds
     * @return
     */
    public static NgsToken checkNgsToken(String token, String ds) throws IllegalAccessException {
        String ngsUrl = config.getUploadUrl().split("/ngs/fs")[0];
        String requestUrl = ngsUrl + "/EliteGeneralHttpTask/api/apiLoginToken";
        log.debug("TokenUtil.checkNgsToken: [tokenUrl: {}, token: {}, ds: {}]", requestUrl, token, ds);
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        params.add(Constants.NGS_TOKEN, StrUtil.emptyIfNull(token));
        params.add(Constants.NGS_DS, StrUtil.nullToDefault(ds, "default"));
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
        return restTemplateService.postForEntity(requestUrl, request, NgsToken.class).getBody();
    }

    /**
     * 从token中获取返回值
     *
     * @param token
     * @param ds
     * @return
     */
    public static NgsToken getNgsToken(String token, String ds) throws IllegalAccessException {
        log.debug("request: with token: [{}], ds: [{}]", token, ds);
        return checkNgsToken(token, ds);

//        ObjectMapper mapper = new ObjectMapper();
//        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
//        return mapper.readValue("{\"code\":1,\"message\":\"\",\"value\":{\"id\":\"000048\",\"name\":\"vikki\",\"agentId\":\"vikki\",\"loginName\":\"vikki\",\"epid\":\"\",\"epidDbPool\":null,\"remoteKey\":\"4554B86F-B968-E210-F390-0C485291AAC7\",\"headImg\":null,\"supervisor\":4,\"rolegroupType\":null,\"loginTime\":1652243213149,\"projects\":[{\"id\":\"default\",\"name\":\"默认项目\",\"token\":\"65c44dcf-f340-4ec9-bd9d-53337cd99ec8$DBMaingoodluck\",\"ordIndex\":12,\"groupId\":\"SYSTEM\",\"groupName\":\"系统组\",\"roles\":[{\"id\":\"G00003\",\"name\":\"公司管理\"},{\"id\":\"G00001\",\"name\":\"管理组\"}]}],\"curProject\":\"default\",\"lsa\":false,\"extra\":null,\"epidSql\":\"\"}}", NgsToken.class);
//        return mapper.readValue("{ \"code\": 1, \"message\": \"\", \"value\": { \"id\": \"SELITE\", \"name\": \"ELITE\", \"agentId\": \"elite\", \"loginName\": \"elite\", \"epid\": \"\", \"epidDbPool\": null, \"remoteKey\": \"AEEF3D18-309D-9590-D8B6-338D51E29AE2\", \"headImg\": null, \"supervisor\": 5, \"rolegroupType\": null, \"loginTime\": 1635157347733, \"projects\": [ { \"id\": \"default\", \"name\": \"默认项目\", \"token\": \"220bc862-d681-4ed1-91bc-97f34a51e05f$DBMaingoodluck\", \"ordIndex\": 23, \"groupId\": \"SYSTEM\", \"groupName\": \"系统组\", \"roles\": [] } ], \"curProject\": \"default\", \"lsa\": false, \"epidSql\": \"\" } }", NgsToken.class);
//        return mapper.readValue("{\"code\":1,\"message\":\"\",\"value\":{\"id\":\"000231\",\"name\":\"VIKKI\",\"agentId\":\"vikki\",\"loginName\":\"vikki\",\"epid\":\"E00008\",\"epidDbPool\":null,\"remoteKey\":\"53A16E42-C324-133D-72A3-B13F7575290C\",\"headImg\":null,\"supervisor\":0,\"rolegroupType\":null,\"loginTime\":1646190431148,\"projects\":[{\"id\":\"default\",\"name\":\"默认项目\",\"token\":\"f25296a2-8b82-4aae-8208-f7d0fe5e019cE00008\",\"ordIndex\":29,\"groupId\":\"SYSTEM\",\"groupName\":\"总部\",\"roles\":[{\"id\":\"G00001\",\"name\":\"管理组\"}]}],\"curProject\":\"default\",\"lsa\":false,\"extra\":null,\"epidSql\":\"_E00008\"}})", NgsToken.class);
//        return mapper.readValue("{\"code\":1,\"message\":\"\",\"value\":{\"id\":\"000015\",\"name\":\"sher\",\"agentId\":\"sher\",\"loginName\":\"sher\",\"epid\":\"\",\"epidDbPool\":null,\"remoteKey\":\"DAB22FEF-623A-4E69-8E7A-8DE65E41D862\",\"headImg\":null,\"supervisor\":1,\"rolegroupType\":null,\"loginTime\":1657779225868,\"projects\":[{\"id\":\"default\",\"name\":\"默认项目\",\"token\":\"f6446b52-fcf5-4ac0-8fea-560dc951c846$DBMaintest\",\"ordIndex\":12,\"groupId\":\"SYSTEM\",\"groupName\":\"系统组\",\"roles\":[]}],\"curProject\":\"default\",\"lsa\":false,\"consolable\":false,\"extra\":{\"STRINGFIELD1\":\"\"},\"epidSql\":\"\"}}", NgsToken.class);
    }

    /**
     * check 是否登录
     *
     * @param request
     * @return
     * @throws KMException
     * @throws JsonProcessingException
     */
    public static UserContainer checkLogined(HttpServletRequest request) throws KMException, JsonProcessingException, IllegalAccessException {
        log.debug("do filter check login");
        HttpSession session = request.getSession(false);
        String lang = session == null ? "" : (String) session.getAttribute("locale");
        Locale locale = config.getUserLocale(lang);
        UserContainer userContainer;
        if (session == null) {
            log.error("当前访问没有session");
            String ngsToken = WebUtil.getString(request, Constants.NGS_TOKEN);
            if (StringUtil.isEmpty(ngsToken)) {
                throw new KMException(Constants.ResultCode.NOT_LOGIN, I18nUtils.get(ERRORMESSAGE, locale));
            }
            return getUserContainer(request);
        } else {
            userContainer = (UserContainer) session.getAttribute(Constants.USER_CONTAINER);
            if (userContainer == null) {
                Staff staff = (Staff) WebUtil.getSessionAttribute(request, STAFF);
                if (staff == null) {
                    throw new KMException(Constants.ResultCode.NOT_LOGIN, I18nUtils.get(ERRORMESSAGE, locale));
                }
                String epId = DSUtils.getEpId((String) session.getAttribute(Constants.EPID));
                userContainer = UserContainer.builder().epId(epId).staff(staff).build();
                session.setAttribute(Constants.USER_CONTAINER, userContainer);
            }
        }
        log.debug("current request has logined");

        // 判断staff是否存在
        if (userContainer.getStaff() == null) {
            throw new KMException(Constants.ResultCode.NOT_LOGIN, I18nUtils.get(ERRORMESSAGE, locale));
        }
        return userContainer;
    }

    public static String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || Constants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || Constants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || Constants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 外部调用个接时 构建userContainer
     *
     * @param request
     * @return
     * @throws KMException
     * @throws JsonProcessingException
     */
    public static UserContainer getUserContainer(HttpServletRequest request) throws KMException, JsonProcessingException, IllegalAccessException {
        UserContainer userContainer = (UserContainer) WebUtil.getSessionAttribute(request, Constants.USER_CONTAINER);
        String ngsToken = WebUtil.getString(request, Constants.NGS_TOKEN);
        if (StringUtil.isEmpty(ngsToken)) {
            String staffId = request.getParameter("staffId");
            String epId = DSUtils.getEpId(request.getParameter(Constants.EPID));
            if (userContainer == null) {
                Staff staff = treeDao.checkStaffWithoutPassword(staffId, epId);
                userContainer = UserContainer.builder().epId(epId).staff(staff).build();
                WebUtil.setSessionAttribute(request, Constants.USER_CONTAINER, userContainer);
            } else {
                Staff staff = userContainer.getStaff();
                if (!StringUtil.isEmpty(staffId) && !staffId.equals(staff.getId())) {
                    // 参数传递了新的staffId，要更换缓存
                    staff = treeDao.checkStaffWithoutPassword(staffId, epId);
                    userContainer.setStaff(staff);
                    if (StringUtil.isNotEmpty(epId)) {
                        userContainer.setEpId(epId);
                    }
                    WebUtil.setSessionAttribute(request, Constants.USER_CONTAINER, userContainer);
                }
            }
        } else {
            String ngsDs = WebUtil.getString(request, Constants.NGS_DS);
            NgsToken ngsTokenObj = TokenUtils.getNgsToken(ngsToken, ngsDs);
            if (userContainer == null) {
                userContainer = setUpLoginSession(request, ngsToken, ngsDs, ngsTokenObj, false);
            } else {
                NgsTokenValue value = ngsTokenObj.getValue();
                String staffId = value.getId();
                String epId = DSUtils.getEpId(value.getEpidSql().toUpperCase());
                Staff staff = userContainer.getStaff();
                if (!StringUtil.isEmpty(staffId) && !staffId.equals(staff.getId())) {
                    // 参数传递了新的staffId，要更换缓存
                    staff = treeDao.checkStaffWithoutPassword(staffId, epId);
                    userContainer.setStaff(staff);
                    if (StringUtil.isNotEmpty(epId)) {
                        userContainer.setEpId(epId);
                    }
                    WebUtil.setSessionAttribute(request, Constants.USER_CONTAINER, userContainer);
                }
            }
        }
        return userContainer;
    }

    public static UserContainer setUpLoginSession(HttpServletRequest request, String token, String ds, NgsToken ngsToken, boolean isPortal) throws KMException {
        NgsTokenValue value = ngsToken.getValue();
        String staffId = value.getId();
        String epIdSql = value.getEpidSql().toUpperCase();
        log.debug("dataSource.epId: [{}]", epIdSql);
        if (config.useLoginName(epIdSql)) {
            String loginName = value.getLoginName();
            log.debug("use login name: {}", loginName);
        }
        Staff staff = treeDao.checkStaffWithoutPassword(staffId, epIdSql);
        UserContainer userContainer = UserContainer.builder().epId(DSUtils.getEpId(epIdSql)).staff(staff).build();
        WebUtil.setSessionAttribute(request, STAFF, staff);
        WebUtil.setSessionAttribute(request, Constants.EPID, DSUtils.getEpId(epIdSql));
        WebUtil.setSessionAttribute(request, Constants.SESSION_NGS_TOKEN, token);
        WebUtil.setSessionAttribute(request, Constants.NGS_DS, ds);
        if (isPortal) {
            try {
                String clientIp = TokenUtils.getClientIp(request);
                articleLockService.unlockAllArticle(epIdSql, staff.getId());
                treeDao.addLoginHis(epIdSql, staff.getId(), clientIp);
            } catch (Exception e) {
                log.error("", e);
            }
        }

        SessionStaff sessionStaff = null;
        String curProject = value.getCurProject();
        // 设置session staff
        if (!CollectionsUtils.isEmpty(value.getProjects())) {
            for (int i = 0; i < value.getProjects().size(); i++) {
                String id = value.getProjects().get(i).getId();
                if (StringUtil.equals(id, curProject)) {
                    log.debug("projects:" + value.getProjects());
                    String staffRoleGroupId = value.getProjects().get(i).getGroupId();
                    userContainer.getStaff().setCurrentRolegroupId(staffRoleGroupId);
                    sessionStaff = new SessionStaff(staffId, value.getName(), staffRoleGroupId);
                    log.debug("sessionStaff:" + sessionStaff);
                    break;
                }
            }
        }
        WebUtil.setSessionAttribute(request, Constants.USER_CONTAINER, userContainer);
        if (sessionStaff == null) {
            sessionStaff = new SessionStaff(staffId, value.getName(), staff.getDefaultRolegroupId());
        }
        WebUtil.setSessionAttribute(request, Constants.SESSION_STAFF, sessionStaff);

        return userContainer;
    }

    public static UserContainer setUpNgs3LoginSession(HttpServletRequest request, LoginUser loginUser, boolean isPortal) throws KMException {
        String staffId = loginUser.getId();
        String epIdSql = StringUtil.parseNull(loginUser.getEpId()).toUpperCase();
        log.debug("dataSource.epId: [{}]", epIdSql);
        if (config.useLoginName(epIdSql)) {
            String loginName = loginUser.getName();
            log.debug("use login name: {}", loginName);
        }
        Staff staff = treeDao.checkStaffWithoutPassword(staffId, epIdSql);
        UserContainer userContainer = UserContainer.builder().epId(DSUtils.getEpId(epIdSql)).staff(staff).build();
        WebUtil.setSessionAttribute(request, STAFF, staff);
        WebUtil.setSessionAttribute(request, Constants.EPID, DSUtils.getEpId(epIdSql));
        WebUtil.setSessionAttribute(request, Constants.SESSION_NGS3_LOGIN_USER, loginUser);
        WebUtil.setSessionAttribute(request, Constants.USER_CONTAINER, userContainer);
        if (isPortal) {
            try {
                String clientIp = TokenUtils.getClientIp(request);
                articleLockService.unlockAllArticle(epIdSql, staff.getId());
                treeDao.addLoginHis(epIdSql, staff.getId(), clientIp);
            } catch (Exception e) {
                log.error("", e);
            }
        }

        // 设置session staff
        SessionStaff sessionStaff = new SessionStaff(staffId, loginUser.getName(), loginUser.getGroupId());
        WebUtil.setSessionAttribute(request, Constants.SESSION_STAFF, sessionStaff);
        return userContainer;
    }
}
